package chapter21.chapter21_7;//: concurrency/SemaphoreDemo.java
// Testing the Pool class

import java.util.concurrent.*;
import java.util.*;

import static net.mindview.util.Print.*;

// A task to check a resource out of a pool:
class CheckoutTask<T> implements Runnable {
    private static int counter = 0;
    private final int id = counter++;
    private Pool<T> pool;

    public CheckoutTask(Pool<T> pool) {
        this.pool = pool;
    }

    public void run() {
        try {
            T item = pool.checkOut();
            print(this + "checked out " + item);
            TimeUnit.SECONDS.sleep(1);
            print(this + "checking in " + item);
            pool.checkIn(item);
        } catch (InterruptedException e) {
            // Acceptable way to terminate
        }
    }

    public String toString() {
        return "CheckoutTask " + id + " ";
    }
}

public class SemaphoreDemo {
    final static int SIZE = 25;

    public static void main(String[] args) throws Exception {
        final Pool<Fat> pool =
                new Pool<Fat>(Fat.class, SIZE);
        ExecutorService exec = Executors.newCachedThreadPool();
        for (int i = 0; i < SIZE; i++)
            exec.execute(new CheckoutTask<Fat>(pool));
        print("All CheckoutTasks created");
        List<Fat> list = new ArrayList<Fat>();
        for (int i = 0; i < SIZE; i++) {
            Fat f = pool.checkOut();
            printnb(i + ": main() thread checked out ");
            f.operation();
            list.add(f);
        }
        Future<?> blocked = exec.submit(new Runnable() {
            public void run() {
                try {
                    // Semaphore prevents additional checkout,
                    // so call is blocked:
                    pool.checkOut();
                } catch (InterruptedException e) {
                    print("checkOut() Interrupted");
                }
            }
        });
        TimeUnit.SECONDS.sleep(2);
        blocked.cancel(true); // Break out of blocked call
        print("Checking in objects in " + list);
        for (Fat f : list)
            pool.checkIn(f);
        for (Fat f : list)
            pool.checkIn(f); // Second checkIn ignored
        exec.shutdown();
    }
} /*
 CheckoutTask 0 checked out Fat id: 0
CheckoutTask 1 checked out Fat id: 2
All CheckoutTasks created
CheckoutTask 2 checked out Fat id: 1
CheckoutTask 3 checked out Fat id: 4
0: main() thread checked out Fat id: 3
1: main() thread checked out Fat id: 5
2: main() thread checked out Fat id: 6
3: main() thread checked out Fat id: 7
4: main() thread checked out Fat id: 8
5: main() thread checked out Fat id: 9
CheckoutTask 4 checked out Fat id: 10
6: main() thread checked out Fat id: 11
7: main() thread checked out Fat id: 12
8: main() thread checked out CheckoutTask 5 checked out Fat id: 13
Fat id: 14
9: main() thread checked out Fat id: 15
10: main() thread checked out Fat id: 16
CheckoutTask 7 checked out Fat id: 18
CheckoutTask 6 checked out Fat id: 17
11: main() thread checked out Fat id: 19
CheckoutTask 8 checked out Fat id: 20
12: main() thread checked out Fat id: 21
13: main() thread checked out Fat id: 22
CheckoutTask 9 checked out Fat id: 23
14: main() thread checked out Fat id: 24
CheckoutTask 1 checking in Fat id: 2
CheckoutTask 10 checked out Fat id: 2
CheckoutTask 0 checking in Fat id: 0
15: main() thread checked out Fat id: 0
CheckoutTask 3 checking in Fat id: 4
CheckoutTask 11 checked out Fat id: 4
CheckoutTask 2 checking in Fat id: 1
CheckoutTask 12 checked out Fat id: 1
CheckoutTask 5 checking in Fat id: 13
CheckoutTask 13 checked out Fat id: 13
CheckoutTask 4 checking in Fat id: 10
CheckoutTask 8 checking in Fat id: 20
CheckoutTask 9 checking in Fat id: 23
CheckoutTask 14 checked out Fat id: 20
CheckoutTask 15 checked out Fat id: 23
CheckoutTask 16 checked out Fat id: 10
CheckoutTask 6 checking in Fat id: 17
CheckoutTask 7 checking in Fat id: 18
CheckoutTask 18 checked out Fat id: 18
CheckoutTask 17 checked out Fat id: 17
CheckoutTask 10 checking in Fat id: 2
CheckoutTask 19 checked out Fat id: 2
CheckoutTask 11 checking in Fat id: 4
CheckoutTask 20 checked out Fat id: 4
CheckoutTask 12 checking in Fat id: 1
CheckoutTask 21 checked out Fat id: 1
CheckoutTask 13 checking in Fat id: 13
CheckoutTask 22 checked out Fat id: 13
CheckoutTask 15 checking in Fat id: 23
CheckoutTask 18 checking in Fat id: 18
CheckoutTask 17 checking in Fat id: 17
CheckoutTask 16 checking in Fat id: 10
CheckoutTask 14 checking in Fat id: 20
16: main() thread checked out Fat id: 17
CheckoutTask 24 checked out Fat id: 18
CheckoutTask 23 checked out Fat id: 23
17: main() thread checked out Fat id: 10
18: main() thread checked out Fat id: 20
CheckoutTask 19 checking in Fat id: 2
CheckoutTask 20 checking in Fat id: 4
CheckoutTask 21 checking in Fat id: 1
19: main() thread checked out Fat id: 2
20: main() thread checked out Fat id: 1
21: main() thread checked out Fat id: 4
CheckoutTask 22 checking in Fat id: 13
22: main() thread checked out Fat id: 13
CheckoutTask 24 checking in Fat id: 18
CheckoutTask 23 checking in Fat id: 23
23: main() thread checked out Fat id: 18
24: main() thread checked out Fat id: 23
checkOut() Interrupted
Checking in objects in [Fat id: 3, Fat id: 5, Fat id: 6, Fat id: 7, Fat id: 8, Fat id: 9, Fat id: 11, Fat id: 12, Fat id: 14, Fat id: 15, Fat id: 16, Fat id: 19, Fat id: 21, Fat id: 22, Fat id: 24, Fat id: 0, Fat id: 17, Fat id: 10, Fat id: 20, Fat id: 2, Fat id: 1, Fat id: 4, Fat id: 13, Fat id: 18, Fat id: 23]*///:~
